package moltencore.network.game;

import moltencore.config.Config;
import moltencore.game.IGameEventListener;
import spark.network.Demon;
import spark.network.Util;
import spark.network.ActiveClientList;
import spark.network.ServerSender;
import spark.network.protocol.*;
import org.apache.log4j.Logger;

import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.DatagramPacket;

import moltencore.network.protocol.*;
import moltencore.game.Game;

public class GameDemon extends Demon implements Runnable {
	private static Logger logger = Logger.getLogger(GameDemon.class);

	private GameDemonHandler handler;
	private StrategyFactory strategyFactory;

	public GameDemon(Game game, GameLobby lobby) throws SocketException {
		super();
		ActiveClientList clients = new ActiveClientList();
		lobby.getPlayers().addAuthorizationListener(clients);
		ServerSender sender = new ServerSender(clients);
		handler = new GameDemonHandler(clients, sender);
		setTimeAdjuster(handler);
		IGameEventListener gameEventListener = new GameEventDistributor(sender);
		lobby.addGameEventListener(gameEventListener);
		game.addGameEventListener(gameEventListener);
		strategyFactory = new StrategyFactory(game, lobby);
	}

	@Override
	protected void processPacket(DatagramPacket packet, long receiveTime) {
		byte[] packetData = packet.getData();
		InetSocketAddress source = Util.extractInetSocketAddress(packet);
		switch(Base.getType(packetData)) {
			case Acknowledgement.TYPE:
				logger.debug("Received: Acknowledgement from " + source);
				handler.handle(Acknowledgement.create(packetData, receiveTime), source);
				break;
			case KeepAlive.TYPE:
				logger.debug("Received: KeepAlive from " + source);
				logger.warn("No handling routine for keep alive");
				break;
			case PreLogin.TYPE:
				logger.debug("Received: PreLogin from " + source);
				handler.handle(PreLogin.create(packetData, receiveTime), source);
				break;
			case PreLoginResponseAck.TYPE:
				logger.debug("Received: PreLoginResponseAck from " + source);
				handler.handle(PreLoginResponseAck.create(packetData, receiveTime), source);
				break;
			case ClockSyncRes.TYPE:
				logger.debug("Received: ClockSyncRes from " + source);
				handler.handle(ClockSyncRes.create(packetData, receiveTime), source);
				break;
			case JoinGame.TYPE:
				logger.debug("Received: JoinGame from " + source);
				handler.handle(JoinGame.create(packetData, receiveTime), source, strategyFactory.getJoinGameStrategy());
				break;
			case JoinTeam.TYPE:
				logger.debug("Received: JoinTeam from " + source);
				handler.handle(JoinTeam.create(packetData, receiveTime), source, strategyFactory.getJoinTeamStrategy());
				break;
			case StartGame.TYPE:
				logger.debug("Received: StartGame from " + source);
				handler.handle(StartGame.create(packetData, receiveTime), source, strategyFactory.getStartGameStrategy());
				break;
			case ReadyToPlay.TYPE:
				logger.debug("Received: ReadyToPlay from " + source);
				handler.handle(ReadyToPlay.create(packetData, receiveTime), source, strategyFactory.getReadyToPlayStrategy());
				break;
			case CannonRotateStart.TYPE:
				logger.debug("Received: CannonRotateStart from " + source);
				handler.handle(CannonRotateStart.create(packetData, receiveTime), source, strategyFactory.getCannonRotateStartStrategy());
				break;
			case CannonRotateEnd.TYPE:
				logger.debug("Received: CannonRotateEnd from " + source);
				handler.handle(CannonRotateEnd.create(packetData, receiveTime), source, strategyFactory.getCannonRotateEndStrategy());
				break;
			case CannonFire.TYPE:
				logger.debug("Received: CannonFire from " + source);
				handler.handle(CannonFire.create(packetData, receiveTime), source, strategyFactory.getCannonFireStrategy());
				break;
			default:
				//TODO : when done with programming the protocol remove this warn message
				//unknown protocol type received, ignore it
				logger.warn("Unknown protocol type received " + Integer.toHexString(Base.getType(packet.getData())) + ". Forgot to handle this protocol type?");
				break;
		}
	}
}
